package cn.boodqian.airreport;

import java.io.IOException;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;

import cn.boodqian.util.Log;

public class AirData implements Serializable {
	private Date time = null;
	private ArrayList<Float> hist_pm25;
	private ArrayList<Float> hist_pm10;
	private ArrayList<Float> hist_so2;
	private ArrayList<Float> hist_no2;
	
	public final long MS_PER_HOUR = 60*60*1000;
	public final int MAX_HOURS = 24; // A month
	
	public AirData(ArrayList<Float> pm25, ArrayList<Float> pm10, ArrayList<Float> so2, ArrayList<Float> no2, Date t) {
		assert(pm25.size() == pm10.size() && pm25.size() == so2.size() && pm25.size() == no2.size());
		
		hist_pm25 = pm25; 
		hist_pm10 = pm10;
		hist_so2 = so2;
		hist_no2 = no2;;
		time = new Date(t.getTime());
	}
	
	public int getLength() {
		return hist_pm25.size();
	}
	
	public List<Float> getPM25() {
		return Collections.unmodifiableList(hist_pm25);
	}
	
	public List<Float> getPM10() {
		return Collections.unmodifiableList(hist_pm10);
	}
	
	public List<Float> getSO2() {
		return Collections.unmodifiableList(hist_so2);
	}
	
	public List<Float> getNO2() {
		return Collections.unmodifiableList(hist_no2);
	}
	
	public Date getTime() {
		return new Date(time.getTime());
	}
	
	public void merge(AirData data) {
		if(data==null || data.getLength() == 0) return;
		
		long currentMaxTime = time.getTime()/MS_PER_HOUR;
		long currentMinTime =  currentMaxTime - (getLength()-1);
		
		long maxTime = data.time.getTime()/MS_PER_HOUR;
		long minTime =  maxTime - (data.getLength()-1);
		
		// Expand the current list to include both time span
		if(maxTime > currentMaxTime) {
			for(long t = currentMaxTime+1;t<=maxTime;t++) {
				hist_pm25.add(0f);
				hist_pm10.add(0f);
				hist_so2.add(0f);
				hist_no2.add(0f);
			}
			currentMaxTime = maxTime;
		}
		else if(minTime < currentMinTime) {
			for(long t = minTime;t<currentMinTime;t++) {
				hist_pm25.add(0, 0f);
				hist_pm10.add(0, 0f);
				hist_so2.add(0, 0f);
				hist_no2.add(0, 0f);
			}
			currentMinTime = minTime;
		}
		time.setTime(currentMaxTime*MS_PER_HOUR);
		if(Log.isLoggable(Log.DEBUG)) Log.d("New time:"+time);
		
		// Replace with new value if it's 0
		for(int i=0;i<data.getLength();i++) {
			long t = minTime + i;
			int index = (int) (t - currentMinTime);
			if(hist_pm25.get(index).compareTo(0f) == 0) {
				Float v = (Float) data.getPM25().get(i);
				hist_pm25.set(index, v);
			}
			if(hist_pm10.get(index).compareTo(0f) == 0) {
				Float v = (Float) data.getPM10().get(i);
				hist_pm10.set(index, v);
			}
			if(hist_so2.get(index).compareTo(0f) == 0) {
				Float v = (Float) data.getSO2().get(i);
				hist_so2.set(index, v);
			}
			if(hist_no2.get(index).compareTo(0f) == 0) {
				Float v = (Float) data.getNO2().get(i);
				hist_no2.set(index, v);
			}
		}
		
		// Cut the data exceed the max capacity MAX_HOURS
		int length = getLength();
		if(length > MAX_HOURS) {
			if(Log.isLoggable(Log.INFO)) Log.i(String.format("%d exceeds max capacity %d, cutting off", length, MAX_HOURS));
			hist_pm25.subList(0, length-MAX_HOURS).clear();
			hist_pm10.subList(0, length-MAX_HOURS).clear();
			hist_so2.subList(0, length-MAX_HOURS).clear();
			hist_no2.subList(0, length-MAX_HOURS).clear();
		}
	}
	
    private void writeObject(java.io.ObjectOutputStream out) throws IOException {
    	out.writeObject(time);
    	out.writeObject(hist_pm25);
    	out.writeObject(hist_pm10);
    	out.writeObject(hist_so2);
    	out.writeObject(hist_no2);
    }

    private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException
    {
    	time = (Date)in.readObject();
    	hist_pm25 = (ArrayList<Float>)in.readObject();
    	hist_pm10 = (ArrayList<Float>) in.readObject();
    	hist_so2 = (ArrayList<Float>) in.readObject();
    	hist_no2 = (ArrayList<Float>) in.readObject();
    }
}
